﻿using System;
using System.Management;
using System.ServiceProcess;

namespace BneyBaruch.Ingest.Core.ServiceProcess
{
    public delegate void ServiceStateChangedEventHandler(object sender, ServiceStateChangedEvent e);

    public class ServiceStateWatcher : IDisposable
    {
        #region Fields

        private readonly string _serviceName;
        private readonly ManagementEventWatcher _eventWatcher = null;
        private ServiceState _serviceState;

        #endregion

        #region Constructors

        public ServiceStateWatcher(string serviceName)
        {
            if (string.IsNullOrEmpty(serviceName))
                throw new ArgumentNullException("serviceName");
            _serviceName = serviceName;

            _eventWatcher = new ManagementEventWatcher(
                    @"SELECT * FROM __InstanceOperationEvent
                        WITHIN 3 WHERE TargetInstance ISA 'Win32_Service' AND Targetinstance.Name =
                        '" + ServiceName + @"'");
            _eventWatcher.EventArrived += new EventArrivedEventHandler(_eventWatcher_EventArrived);
            _eventWatcher.Start();

            RecognizeServiceStateFirstTime();
        }

        #endregion

        #region Properties

        public string ServiceName
        {
            get
            {
                return _serviceName;
            }
        }

        public ServiceState State
        {
            get
            {
                return _serviceState;
            }
            private set
            {
                _serviceState = value;
                if( StateChanged != null )
                    StateChanged(this,new ServiceStateChangedEvent(_serviceState));
            }
        }

        #endregion

        #region Private Methods

        void _eventWatcher_EventArrived(object sender, EventArrivedEventArgs e)
        {
            ManagementBaseObject serviceInstance = e.NewEvent["TargetInstance"] as ManagementBaseObject;
            if (serviceInstance != null)
            {
                string state = serviceInstance.Properties["State"].Value.ToString();
                State = (ServiceState)Enum.Parse(typeof(ServiceState), state);
            }
        }

        private void RecognizeServiceStateFirstTime()
        {
            using (ServiceController serviceController = new ServiceController(ServiceName))
            {
                State = (ServiceState)Enum.Parse(typeof(ServiceState), serviceController.Status.ToString());
                serviceController.Close();
            }
        }

        #endregion

        #region Events

        public event ServiceStateChangedEventHandler StateChanged;

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            if (_eventWatcher != null)
            {
                try
                {
                    _eventWatcher.Stop();
                }
                finally
                {
                    _eventWatcher.Dispose();
                }
            }
        }

        #endregion
    }
}
